package com.yuand.core;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.yuand.entity.SysUser;
import com.yuand.utils.IdUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author yuandong
 * @date 2021/9/10 11:18
 * Jwt工具类
 */
@Service
public class JwtService {

    // 令牌秘钥
    @Value("${jwt.secret}")
    private String secret;

    // 令牌有效期（默认30分钟）
    @Value("${jwt.expireTime}")
    private int expireTime;

    protected static final long MILLIS_SECOND = 1000;

    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;


    @Autowired
    private RedisService redisService;

    /**
     * 校验token是否正确
     *
     * @param token 密钥
     * @return 是否正确
     */
    public  boolean verify(String token) throws Exception {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            System.out.println(jwt);
            return true;
        } catch (TokenExpiredException tokenExpiredException) {
            throw new Exception("token已过期");
        } catch (SignatureVerificationException signatureVerificationException) {
            throw new Exception("token验证失败");
        } catch (JWTDecodeException jwtDecodeException) {
            throw new Exception("token解析失败");
        } catch (Exception exception) {
            exception.printStackTrace();
            throw new Exception("未登录");
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名,30分钟后过期
     *
     * @param username 用户名
     * @return 加密的token
     */
    public  String createToken(String username) {
        Date date = new Date(System.currentTimeMillis() + expireTime * MILLIS_MINUTE);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带username信息
        return JWT.create()
                .withClaim("username", username)
                .withExpiresAt(date)
                .sign(algorithm);
    }




    /**
     * 从令牌中获取数据声明
     * @param token 令牌
     * @return 数据声明
     */
    private Claims parseToken(String token){
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }



    /**
     * 从令牌中获取用户名
     * @param token 令牌
     * @return 用户名
     */
    public String getUsernameFromToken(String token){
        Claims claims = parseToken(token);
        return claims.getSubject();
    }


    /**
     * 刷新令牌有效期  还没写完
     * @param user 登录信息
     */
    public void refreshToken(SysUser user)
    {
        user.setLoginTime(System.currentTimeMillis());  //当前时间
        user.setExpireTime(user.getLoginTime() + expireTime * MILLIS_MINUTE);   //过期时间
        // 根据uuid将当前用户缓存起来
        String userKey = "user_token:"+ IdUtils.fastUUID();
        redisService.set(userKey, user, expireTime);

    }

}




